package service

import (
	"context"
	"fmt"
	"github.com/pkg/errors"
	"gorm.io/gorm"
	"prod/api/prod"
	"prod/internal/constant"
	"prod/internal/model"
	"prod/pkg/ecode"
	"prod/pkg/util"
	"strconv"
	"strings"
)

func (s *Service) SelectionProdTypes(ctx context.Context, req *prod.SelectionProdTypesRequest) (
	resp *prod.SelectionProdTypesResponse, err error) {
	resp = &prod.SelectionProdTypesResponse{}
	if len(req.Ids) != 0 {
		if resp.ProdTypes, err = s.dao.GetSimpleProdTypeByIDsWithoutPStoreId(
			ctx, req.Ids, req.Token.SgId); err != nil {
			return
		}
	} else {
		if resp.ProdTypes, err = s.dao.GetSimpleProdTypeList(ctx, req.Token.SgId, req.PStoreId); err != nil {
			return
		}
	}
	return
}

func (s *Service) SelectionProdsFull(ctx context.Context, req *prod.SelectionProdListRequest) (
	resp *prod.SelectionProdsFullResponse, err error) {
	var (
		prods []*model.ProdQueryModel
		skus  []*model.Sku
	)
	if prods, err = s.dao.GetSelectProdsByIDs(ctx, req.Ids, req.SgId); err != nil {
		return
	}
	resp = &prod.SelectionProdsFullResponse{Prods: make([]*prod.SelectionProdView, len(prods))}
	for i, product := range prods {
		product.SelectionProdView.GroupList = product.Groups
		product.SelectionProdView.GroupDetail = product.GroupJson
		resp.Prods[i] = product.SelectionProdView
	}

	if skus, err = s.dao.GetProdSkusByProdIds(ctx, req.Ids, req.SgId); err != nil {
		return
	}
	skuMap := make(map[uint64][]*prod.SelectionSkuSimpleView)
	for _, sku := range skus {
		if _, ok := skuMap[sku.ProdId]; !ok {
			skuMap[sku.ProdId] = make([]*prod.SelectionSkuSimpleView, 0)
		}
		skuMap[sku.ProdId] = append(skuMap[sku.ProdId], &prod.SelectionSkuSimpleView{
			Id:     sku.ID,
			Name:   strings.Join(sku.Items, "/"),
			Price:  sku.Price,
			Weight: sku.Weight,
			Items:  sku.Items,
		})
	}
	for _, product := range resp.Prods {
		if skuList, ok := skuMap[product.Id]; ok {
			product.Skus = skuList
		}
	}
	if req.NeedStorePrice {
		if resp.CustomSkus, err = s.dao.FindStoreCustomPrice(ctx, req.Ids); err != nil {
			return
		}
	}
	return
}

// 商城rpc门店模式获取供货组商品列表
func (s *Service) SelectionMenuProdList(ctx context.Context, req *prod.SelectionMenuProdListRequest) (
	resp *prod.GetProdListResponse, err error) {
	if req.PStoreId == 0 {
		err = ecode.BadRequest("总部模式不能直接匹配供货组")
		return
	}
	var menuStore *model.MenuStore
	if menuStore, err = s.dao.GetMenuStore(ctx, req.PStoreId); err != nil {
		if errors.Cause(err) == gorm.ErrRecordNotFound {
			err = nil
			resp = &prod.GetProdListResponse{
				Total: 0,
				Prods: []*prod.SimpleProdView{},
			}
			return
		}
		return
	}
	resp, err = s.GetMenuProdList(ctx, &prod.GetMenuProdListRequest{
		Token:           &prod.WebToken{SgId: req.SgId},
		PStoreId:        0,
		MenuId:          menuStore.MenuId,
		PageNo:          req.PageNo,
		PageSize:        req.PageSize,
		ProdTypeId:      req.QueryTypeId,
		Query:           req.Query,
		ExcludedProdIds: req.ProdIds,
	})
	return
}

func (s *Service) SelectionMenuProdsFull(ctx context.Context, req *prod.SelectionMenuProdFullRequest) (
	resp *prod.SelectionProdsFullResponse, err error) {
	var (
		menuStore *model.MenuStore
		prods     []*model.ProdQueryModel
		menuSkus  []*model.MenuSkuQueryModel
	)
	if menuStore, err = s.dao.GetMenuStore(ctx, req.PStoreId); err != nil {
		if errors.Cause(err) == gorm.ErrRecordNotFound {
			err = constant.ErrObjectNotExist
			return
		}
		return
	}
	if prods, err = s.dao.GetSelectProdsByIDs(ctx, req.Ids, req.SgId); err != nil {
		return
	}
	resp = &prod.SelectionProdsFullResponse{Prods: make([]*prod.SelectionProdView, len(prods))}
	for i, product := range prods {
		product.SelectionProdView.GroupList = product.Groups
		product.SelectionProdView.GroupDetail = product.GroupJson
		resp.Prods[i] = product.SelectionProdView
	}

	if menuSkus, err = s.dao.GetMenuSkuInfoByProdIds(ctx, menuStore.MenuId, req.Ids); err != nil {
		return
	}
	skuMap := make(map[uint64][]*prod.SelectionSkuSimpleView)
	for _, sku := range menuSkus {
		if _, ok := skuMap[sku.ProdId]; !ok {
			skuMap[sku.ProdId] = make([]*prod.SelectionSkuSimpleView, 0)
		}
		var price uint32
		if sku.MenuPrice.Valid {
			price = uint32(sku.MenuPrice.Int64)
		} else {
			price = sku.SkuPrice
		}
		skuMap[sku.ProdId] = append(skuMap[sku.ProdId], &prod.SelectionSkuSimpleView{
			Id:     sku.SkuId,
			Name:   strings.Join(sku.Items, "/"),
			Price:  price,
			Weight: sku.Weight,
			Items:  sku.Items,
		})
	}
	for _, product := range resp.Prods {
		if skuList, ok := skuMap[product.Id]; ok {
			product.Skus = skuList
		} else {
			err = constant.ErrSystemError
			return
		}
	}
	return
}

func (s *Service) SelectionObjectList(ctx context.Context, req *prod.SelectionObjectListRequest) (
	resp *prod.SelectionObjectListResponse, err error) {
	skuIds := make([]uint64, len(req.ObjectKeys))
	prodIDMap := make(util.Int64BoolMap)
	for i, objectKey := range req.ObjectKeys {
		var prodKey, skuKey int
		rawKeys := strings.SplitN(objectKey, "-", 2)
		if prodKey, err = strconv.Atoi(rawKeys[0]); err != nil {
			err = ecode.WithStack(err)
			return
		}
		if skuKey, err = strconv.Atoi(rawKeys[1]); err != nil {
			err = ecode.WithStack(err)
			return
		}
		prodIDMap[uint64(prodKey)] = true
		skuIds[i] = uint64(skuKey)
	}
	var (
		prods []*model.ProdQueryModel
		skus  []*model.Sku
	)
	if prods, err = s.dao.GetSelectProdsByIDs(ctx, prodIDMap.GetKeys(), req.SgId); err != nil {
		return
	}
	if skus, err = s.dao.GetProdSkusBySkuIds(ctx, skuIds, req.SgId); err != nil {
		return
	}
	prodMap := make(map[uint64]*model.ProdQueryModel)
	for _, product := range prods {
		prodMap[product.Id] = product
	}
	resp = &prod.SelectionObjectListResponse{
		Objects: make([]*prod.SelectionObjectView, len(skus))}
	for i, sku := range skus {
		product := prodMap[sku.ProdId]
		resp.Objects[i] = &prod.SelectionObjectView{
			Id:       fmt.Sprintf("%d-%d", product.Id, sku.ID),
			Price:    sku.Price,
			TypeId:   product.ProdTypeId,
			TypeName: product.ProdTypeName,
			Unit:     product.Unit,
			PStoreId: product.PStoreId,
			Name:     product.Name,
			SkuName:  strings.Join(sku.Items, "/"),
		}
	}
	return
}

func (s *Service) SelectionProdInfo(ctx context.Context, req *prod.SelectionProdInfoRequest) (
	resp *prod.ProdView, err error) {
	resp, err = s.getProdInfo(ctx, req.ProdId, req.SgId, req.PStoreId, req.SkipCheck)
	return
}

func (s *Service) CheckStoreMenuProperty(ctx context.Context, req *prod.CommonRequest) (
	resp *prod.CheckStoreMenuPropertyResp, err error) {
	if req.PStoreId == 0 {
		resp = &prod.CheckStoreMenuPropertyResp{
			CanModifyPrice: true,
			HasMenu:        false,
		}
		return
	}
	var menuStore *model.MenuStore
	if menuStore, err = s.dao.GetMenuStore(ctx, req.PStoreId); err != nil {
		if errors.Cause(err) == gorm.ErrRecordNotFound {
			err = nil
			// 自营&平台模式&未启用供货组，视为允许改价
			resp = &prod.CheckStoreMenuPropertyResp{
				CanModifyPrice: true,
				HasMenu:        false,
			}
			return
		}
		return
	} else {
		var menu *model.Menu
		if menu, err = s.dao.GetMenuById(ctx, menuStore.MenuId, req.Token.SgId); err != nil {
			return
		}
		resp = &prod.CheckStoreMenuPropertyResp{
			CanModifyPrice: menu.CanModifyPrice,
			HasMenu:        true,
		}
	}
	return
}
